package ace.module.oauth2.server.test.core.controller;

import ace.cmp.core.model.R;
import ace.cmp.security.oauth2.resource.server.core.annotation.PreAuthorizeIsInternalClient;
import ace.cmp.security.oauth2.resource.server.core.annotation.PreAuthorizeIsUserAuthenticated;
import ace.cmp.security.oauth2.resource.server.core.service.Oauth2SecurityService;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author caspar
 * @date 2023/2/14 10:58
 */
@RestController
@AllArgsConstructor
public class OAuth2ResourceTestController {

  public static final String NO_AUTH_URI = "/auth/test/oauth2/on/auth";
  public static final String AUTHENTICATED_URI = "/auth/test/oauth2/authenticated";
  public static final String AUTHENTICATED_READ_URI = "/auth/test/oauth2/authenticated/read";
  public static final String AUTHENTICATED_NO_READ_URI = "/auth/test/oauth2/authenticated/no/read";
  public static final String AUTHENTICATED_CLIENT_URI = "/auth/test/oauth2/authenticated/client";
  public static final String AUTHENTICATED_USERINFO_URI =
      "/auth/test/oauth2/authenticated/userinfo";
  public static final String AUTHENTICATED_USERINFO_SECURITY_SERVICE_URI =
      "/auth/test/oauth2/authenticated/userinfo/security-service";
  public static final String AUTHENTICATED_ANONYMOUS_LOGIN_TO_USERINFO_URI =
      "/auth/test/oauth2/authenticated/anonymous-login-to-userinfo";
  public static final String AUTHENTICATED_ANONYMOUS_LOGIN_TO_FAIL_URI =
      "/auth/test/oauth2/authenticated/anonymous-login-to-fail";
  public static final String AUTHENTICATED_ANONYMOUS_AND_USERINFO_URI =
      "/auth/test/oauth2/authenticated/anonymous-and-userinfo";
  public static final String AUTHENTICATED_BOOK_SERVICE_HAS_PERMIT_URI =
      "/auth/test/oauth2/authenticated/book-service-has-permit";

  private final Oauth2SecurityService securityService;

  @GetMapping(NO_AUTH_URI)
  public R<String> noAuth() {
    return R.ok("success");
  }

  @PreAuthorize("isAuthenticated()")
  @GetMapping(AUTHENTICATED_URI)
  public R<String> authenticated() {
    return R.ok("success");
  }

  @PreAuthorize("hasAuthority('read')")
  @GetMapping(AUTHENTICATED_READ_URI)
  public R<String> authenticatedRead() {
    return R.ok("success");
  }

  @PreAuthorize("hasAuthority('no_read')")
  @GetMapping(AUTHENTICATED_NO_READ_URI)
  public R<String> authenticatedNoRead() {
    return R.ok("success");
  }

  @PreAuthorizeIsInternalClient
  @GetMapping(AUTHENTICATED_CLIENT_URI)
  public R<String> authenticatedClient() {
    return R.ok("success");
  }

  @PreAuthorizeIsUserAuthenticated
  @GetMapping(AUTHENTICATED_USERINFO_URI)
  public R<String> authenticatedUserInfo() {
    return R.ok("success");
  }

  @PreAuthorize("permitAll()")
  @GetMapping(AUTHENTICATED_USERINFO_SECURITY_SERVICE_URI)
  public R<String> authenticatedUserInfoWithSecurityService() {
    if (!securityService.hasAuthority("read")) {
      throw new RuntimeException("权限不足");
    }
    return R.ok("success");
  }

  @GetMapping(AUTHENTICATED_ANONYMOUS_LOGIN_TO_USERINFO_URI)
  public R<String> authenticatedUserInfoWithAnonymous() {
    if (securityService.hasAuthority("read")) {
      throw new RuntimeException("逻辑错误，不应该有权限");
    }

    securityService.login();
    securityService.getAuthentication();

    if (!securityService.hasAuthority("read")) {
      throw new RuntimeException("逻辑错误：权限不足，这应该有权限");
    }

    return R.ok("success");
  }

  @PreAuthorize("permitAll()")
  @GetMapping(AUTHENTICATED_ANONYMOUS_LOGIN_TO_FAIL_URI)
  public R<String> authenticatedAnonymousWithLoginToFail() {
    if (securityService.hasAuthority("read")) {
      throw new RuntimeException("逻辑错误，不应该有权限");
    }
    securityService.login();
    securityService.getAuthentication();

    if (!this.securityService.isAnonymous()) {
      throw new RuntimeException("逻辑错误：应该登录失败，应该是匿名用户");
    }
    if (securityService.hasAuthority("read")) {
      throw new RuntimeException("逻辑错误：这应该没有权限");
    }

    return R.ok("success");
  }

  @PreAuthorize("permitAll()")
  @GetMapping(AUTHENTICATED_ANONYMOUS_AND_USERINFO_URI)
  public R<String> authenticatedAnonymousAndUserInfo(@RequestParam("checkType") String checkType) {
    if ("checkAnonymous".equals(checkType)) {
      if (!securityService.isAnonymous()) {
        throw new RuntimeException("逻辑错误，应该是匿名用户");
      }
    } else if ("checkUserInfo".equals(checkType)) {
      if (securityService.isAnonymous()) {
        throw new RuntimeException("逻辑错误，应该是正常用户");
      }
    } else {
      throw new RuntimeException("请输入正确的checkType参数");
    }

    return R.ok("success");
  }

  @PreAuthorize("hasAuthority('read_no')")
  @GetMapping(AUTHENTICATED_BOOK_SERVICE_HAS_PERMIT_URI)
  public R<String> authenticatedServiceHasAuthority() {
    return R.ok("success");
  }
}
